﻿#region Copyright (c) 2003 - 2008, Andreas Mueller
/////////////////////////////////////////////////////////////////////////////////////////
// 
// Copyright (c) 2003 - 2008, Andreas Mueller.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// Contributors:
//    Andreas Mueller - initial API and implementation
//
// 
// This software is derived from software bearing the following
// restrictions:
// 
// Copyright (c) 1994
// Hewlett-Packard Company
// 
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation.  Hewlett-Packard Company makes no
// representations about the suitability of this software for any
// purpose.  It is provided "as is" without express or implied warranty.
// 
// 
// Copyright (c) 1996,1997
// Silicon Graphics Computer Systems, Inc.
// 
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation.  Silicon Graphics makes no
// representations about the suitability of this software for any
// purpose.  It is provided "as is" without express or implied warranty.
// 
// 
// (C) Copyright Nicolai M. Josuttis 1999.
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// 
/////////////////////////////////////////////////////////////////////////////////////////
#endregion


using System.Collections;
using NStl.Iterators;
using NUnit.Framework;

namespace NStl.NUnit.Support
{
    /// <summary>
    /// An abstract fixture to test any <see cref="IInputIterator{T}"/> implementation.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class InputIteratorFixture<T>
    {
        /// <summary>
        /// Create an begin iterator for the range that this test runs on.
        /// </summary>
        protected abstract IInputIterator<T> CreateInputBegin();
        /// <summary>
        /// Create an end iterator for the range that this test runs on.
        /// </summary>
        protected abstract IInputIterator<T> CreateInputEnd();
        
        protected IInputIterator<T> begin;
        protected IInputIterator<T> end;
        protected T[] referenceArray;
        
        [SetUp]
        public virtual void SetUp()
        {
            begin = CreateInputBegin();
            end   = CreateInputEnd();
            referenceArray = CreateReferenceArray();
        }

        protected abstract T[] CreateReferenceArray();
        [Test]
        public void RangeHasContent()
        {
            CollectionAssert.IsNotEmpty(NStlUtil.Collection(begin, end));
        }
        [Test]
        public void EqualsHandlesNull()
        {
            Assert.IsFalse(begin.Equals(null));
        }

        [Test]
        public void CloneInputIterator()
        {
            IInputIterator<T> itClone = (IInputIterator<T>)begin.Clone();
            Assert.AreNotSame(itClone, begin);
            Assert.AreEqual(referenceArray[0], itClone.Value);
        }

        [Test]
        public void CloneInputIteratorEndIterator()
        {
            IInputIterator<T> itClone = (IInputIterator<T>)end.Clone();
            Assert.AreNotSame(itClone, end);
            Assert.AreEqual(itClone, end);

            //NeverCalled(itClone.Value);// should throw DereferenceEndIteratorException!!
        }
        protected static void NeverCalled(object o)
        {
            Assert.Fail("This Method should never be called!! It is just a sink for R# warnings!!");
            NeverCalled(o);
        }
        [Test]
        public void CloneInputIteratorWhenMovedBefore()
        {
            begin.PreIncrement();
            begin.PostIncrement();

            Assert.AreEqual(referenceArray[2], begin.Value);

            IInputIterator<T> itClone = (IInputIterator<T>)begin.Clone();
            Assert.AreEqual(referenceArray[2], itClone.Value);
        }

        [Test]
        public void CloneInputIteratorBeforeFirstMove()
        {
            IInputIterator<T> itClone = (IInputIterator<T>)begin.Clone();

            begin.PreIncrement();
            begin.PostIncrement();

            Assert.AreEqual(referenceArray[2], begin.Value);

            Assert.AreEqual(referenceArray[0], itClone.Value);
        }

        [Test]
        public void PreIncrementInputIterator()
        {
            IInputIterator<T> other = begin.PreIncrement();
            Assert.AreSame(other, begin);
            Assert.AreEqual(other, begin);
            Assert.AreEqual(referenceArray[1], other.Value);
        }

        [Test]
        public void PostIncrementInputIterator()
        {
            IInputIterator<T> other = begin.PostIncrement();
            Assert.AreNotSame(other, begin);
            Assert.AreNotEqual(other, begin);

            Assert.AreEqual(referenceArray[0], other.Value);
            Assert.AreEqual(referenceArray[1], begin.Value);
        }

        [Test]
        public void IterateInputIterator()
        {
            ArrayList target = new ArrayList();
            while (!begin.Equals(end))
            {
                target.Add(begin.Value);
                begin.PreIncrement();
            }

            begin = CreateInputBegin();
            CollectionAssert.AreEqual(NStlUtil.Collection(begin, end), target);
        }

        [Test]
        public void IteratePartialInputIterator()
        {
            begin = NStlUtil.Advance<T, IInputIterator<T>>(begin, 3);
            IInputIterator<T> clonedBegin = (IInputIterator<T>)begin.Clone();
            
            ArrayList target = new ArrayList();
            while (!begin.Equals(end))
            {
                target.Add(begin.Value);
                begin.PreIncrement();
            }

            CollectionAssert.AreEqual(NStlUtil.Collection(clonedBegin, end), target);
        }
        //[Test]
        //[ExpectedException(typeof(DereferenceEndIteratorException))]
        //public void DereferenceEndInputIterator()
        //{
        //    NeverCalled(end.Value);// should throw DereferenceEndIteratorException!!
        //}
        //[Test]
        //public void MoveInputIteratorBehindEnd()
        //{
        //    // ... In C++ it is possible to move behind the end
        //    end.PostIncrement();
        //    Assert.AreEqual(end, CreateInputEnd());
        //}
    }
}
